/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/
package org.activequant.data.util;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

import org.activequant.core.domainmodel.data.MarketDataEntity;
import org.activequant.data.retrieval.ISubscription;
import org.activequant.util.pattern.events.IEventListener;
import org.apache.log4j.Logger;

/**
 * Common base for CSV series writers.<br/>
 * abstract class CSVWriterBase&lt;T extends MarketDataEntity&lt;T&gt;&gt;. Holds the following associated variables:
 * <ul>
 * <li>delimiter(String)</li>
 * <li>fileName(String)</li>
 * <li>writer(BufferedWriter)</li>
 * <li>subscription(ISubscription&lt;T&gt;)</li>
 * </ul>
 * <p>
 * <b>History:</b><br>
 *  - [20.12.2007] Created (Mike Kroutikov)<br>
 *
 *  @author Mike Kroutikov
 */
public abstract class CSVWriterBase<T extends MarketDataEntity<T>> {

    protected final Logger log = Logger.getLogger(getClass());
    /**
     * private final static String DEFAULT_DELIMITER = ",";
     */
    private final static String DEFAULT_DELIMITER = ",";
    /**
     * private String delimiter = DEFAULT_DELIMITER;
     */
	private String delimiter = DEFAULT_DELIMITER;
	/**
	 * private String fileName;
	 */
	private String fileName;
	/**
	 * returns the associated delimiter(String)
	 * @return
	 */
	public String getDelimiter() {
		return delimiter;
	}
	/**
	 * sets the associated delimiter(String) with the given delimiter(String)
	 * @param delimiter
	 */
	public void setDelimiter(String delimiter) {
		this.delimiter = delimiter;
	}
    /**
     * returns the associated fileName(String)
     * @return
     */
	public String getFileName() { 
		return fileName;
	}
	/**
	 * sets the associated fileName(String) with the given val(String)
	 * @param val
	 */
	public void setFileName(String val) {
		fileName = val;
	}
	/**
	 * an abstract method
	 * @param entity
	 * @param delimiter
	 * @return
	 */
	protected abstract String formatEntity(T entity, String delimiter);
	/**
	 * an abstract method
	 * @return
	 * @throws Exception
	 */
	protected abstract ISubscription<T> openSubscription() throws Exception;
	/**
	 * an abstract method
	 * @param writer
	 * @throws IOException
	 */
	protected abstract void writeHeader(Writer writer) throws IOException ;
	/**
	 * private BufferedWriter writer;
	 */
	private BufferedWriter writer;
	/**
	 * private ISubscription&lt;T&gt; subscription;
	 */
	private ISubscription<T> subscription;

	/**
	 * Initializes the object by subscribing to the data feed, and preparing
	 * to write to the file. If using Spring, declare this method as bean's "init-method".<br/>
	 * <strong>1.</strong> Initializes the associated writer(BufferedWriter) pointing to the associated fileName(String).<br/>
	 * <strong>2.</strong> Opens and activates the associated subscription(ISubscription&lt;T&gt;) with a listener that
	 * writes every fired event into the writer(BufferedWriter) using the associated delimiter(String)
	 * @throws Exception if can not open file for writing.
	 */
	public void init() throws Exception {
		writer = new BufferedWriter(new FileWriter(fileName));
		writeHeader(writer);
		
		subscription = openSubscription();
		subscription.addEventListener(new IEventListener<T>() {

			public void eventFired(T event) {
				log.debug("entity: " + event);
				
				try {
					writer.write(formatEntity(event, delimiter));
					writer.flush();
				} catch(IOException ex) {
					throw new RuntimeException(ex);
				}
			}
		});
		subscription.activate();
	}
	
	/**
	 * De-initializes the object by canceling data feed subscription and
	 * flushing data to the disk.
	 * If using Spring, declare this method as bean's "destroy-method".<br/>
	 * Cancels the associated subscription(ISubscription&lt;T&gt;) and flushes/closes the associated writer(BufferedWriter)
	 * @throws IOException on IO error.
	 */
	public void destroy() throws IOException {
		subscription.cancel();
		writer.flush();
		writer.close();
	}
}